﻿using ServicesWatchDog.Properties;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ServicesWatchDog
{
    public partial class frmMain : Form
    {

        public const string SERVICE_SEPERATOR = " / Current status: ";
        public const char SERVICE_SEPERATOR_CHAR = '/';

        //Global variables;
        private bool _dragging = false;
        private Point _start_point = new Point(0, 0);
        private bool _firstTime = true;
        private NotifyIcon mynotifyicon = new NotifyIcon();

        private List<ServiceDetails> selectedServices = new List<ServiceDetails>();

        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            mynotifyicon.BalloonTipIcon = ToolTipIcon.Info;
            mynotifyicon.BalloonTipTitle = "Service-WatchDog";
            mynotifyicon.BalloonTipText = "I am alive and watching your services for you.";
            mynotifyicon.Text = "Service-WatchDog";
            mynotifyicon.Icon = ((System.Drawing.Icon)(Resources.Logo)); //The tray icon to use
            mynotifyicon.DoubleClick += Mynotifyicon_DoubleClick;
        }

        private void Mynotifyicon_DoubleClick(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;
            mynotifyicon.Visible = false;
        }

        private void frmMain_MouseDown(object sender, MouseEventArgs e)
        {
            _dragging = true;  // _dragging is your variable flag
            _start_point = new Point(e.X, e.Y);
        }

        private void frmMain_MouseUp(object sender, MouseEventArgs e)
        {
            _dragging = false;
        }

        private void frmMain_MouseMove(object sender, MouseEventArgs e)
        {
            if (_dragging)
            {
                Point p = PointToScreen(e.Location);
                Location = new Point(p.X - this._start_point.X, p.Y - this._start_point.Y);
            }
        }

        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show ("Are you sure you want to close WatchDog. Once, closed the watchdog will not be monitoring your services untill next run.", "Important!", MessageBoxButtons.OKCancel) == DialogResult.OK)
            {
                Application.Exit();
            }
        }

        public static bool IsAdministrator()
        {
            return (new WindowsPrincipal(WindowsIdentity.GetCurrent()))
                    .IsInRole(WindowsBuiltInRole.Administrator);
        }

        private void frmMain_Activated(object sender, EventArgs e)
        {
            if (_firstTime)
            {
                _firstTime = false;
                if (!IsAdministrator())
                {
                    MessageBox.Show("Please execute the application as Administrator.", "Run as Administrator!");                    
                }
                timer1.Start();
                //backgroundWorker1.RunWorkerAsync();
            }
        }

        private void addServiceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmAddService addServiceDialog = new frmAddService();

            addServiceDialog.ShowDialog();

            if (addServiceDialog.selectedServiceDetails != null)
            {
                DisplayServiceDetail(addServiceDialog.selectedServiceDetails);

                selectedServices.Add(addServiceDialog.selectedServiceDetails);
            }
        }

        private void lstServices_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private string ServiceStatus (string ServiceName)
        {
            ServiceController sc = new ServiceController(ServiceName);

            if (sc != null)
            {
                switch (sc.Status)
                {
                    case ServiceControllerStatus.ContinuePending:
                        return "Continue Pending";
                    case ServiceControllerStatus.Paused:
                        return "Paused";
                    case ServiceControllerStatus.PausePending:
                        return "Pause Pending";
                    case ServiceControllerStatus.Running:
                        return "Running";
                    case ServiceControllerStatus.StartPending:
                        return "Start Pending";
                    case ServiceControllerStatus.Stopped:
                        return "Stopped";
                    case ServiceControllerStatus.StopPending:
                        return "Stop Pending";
                }
            }

            return string.Empty;
        }

        private void DisplayServiceDetail(ServiceDetails service, bool performOperations = false)
        {
            bool itemFound = false;

            for (int i = 0; i < lstServices.Items.Count; i++)
            {
                string listItem = lstServices.Items[i].ToString();

                if (listItem.StartsWith(service.Title))
                {
                    itemFound = true;
                    lstServices.Items[i] = string.Concat(service.Title, SERVICE_SEPERATOR, ServiceStatus(service.Name));
                }
            }

            if (!itemFound)
            {
                lstServices.Items.Add(string.Concat(service.Title, SERVICE_SEPERATOR, ServiceStatus(service.Name)));
            }

            if (performOperations)
            {
                if (service.RunWhenStopped)
                {
                    StartService(service);
                }

                if (service.Notify)
                {
                    // Yet to be implemented
                    MessageBox.Show("Feature not implemented");
                }
            }
        }

        private void StartService(ServiceDetails service)
        {
            ServiceController serviceHandler = new ServiceController(service.Name);

            if ((serviceHandler != null) && (serviceHandler.Status != ServiceControllerStatus.Running))
            {
                try
                {
                    serviceHandler.Start();

                    TimeSpan timeout = TimeSpan.FromMilliseconds(30000);
                    //serviceHandler.WaitForStatus(ServiceControllerStatus.Running, timeout);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            int counter = 1;
            foreach (ServiceDetails service in selectedServices)
            {
                backgroundWorker1.ReportProgress(counter / selectedServices.Count, service);

                counter++;
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progressIndicator.Visible = false;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            progressIndicator.Visible = true;
            backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ServiceDetails service = e.UserState as ServiceDetails;

            DisplayServiceDetail(service, true);
        }

        private void lstServices_MouseUp(object sender, MouseEventArgs e)
        {
            lstServices.SelectedIndex = lstServices.IndexFromPoint(e.X, e.Y);

            if (lstServices.SelectedIndex > -1)
            {
                if (e.Button == MouseButtons.Right)
                {
                    string SelectedService = GetServiceTitleFromList(lstServices.SelectedItem.ToString());

                    if (!SelectedService.Equals(string.Empty))
                    {
                        int serviceIndex = ServiceDetails.FindIndexByTitle(SelectedService, selectedServices);

                        if (serviceIndex > -1)
                        {
                            runWhenStoppedToolStripMenuItem.Checked = selectedServices[serviceIndex].RunWhenStopped;

                            notifyMeWhenStoppedToolStripMenuItem.Checked = selectedServices[serviceIndex].Notify;
                        }
                    }
                    rightClickMenu.Show(Cursor.Position);
                }
            }
        }

        private void runWhenStoppedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string SelectedService = GetServiceTitleFromList(lstServices.SelectedItem.ToString ());

            if (!SelectedService.Equals(string.Empty))
            {
                int serviceIndex = ServiceDetails.FindIndexByTitle(SelectedService, selectedServices);

                if (serviceIndex > -1)
                {
                    selectedServices[serviceIndex].RunWhenStopped = !selectedServices[serviceIndex].RunWhenStopped;
                }
            }
        }

        private string GetServiceTitleFromList (string selectedItem)
        {
            string serviceName = string.Empty;

            if (!selectedItem.Equals (string.Empty))
            {
                string[] serviceSegments = selectedItem.Split(SERVICE_SEPERATOR_CHAR);

                if (serviceSegments.Length > 1)
                {
                    serviceName = serviceSegments[0].Trim();
                }
            }

            return serviceName;
        }

        private void notifyMeWhenStoppedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string SelectedService = GetServiceTitleFromList(lstServices.SelectedItem.ToString());

            if (!SelectedService.Equals(string.Empty))
            {
                int serviceIndex = ServiceDetails.FindIndexByTitle(SelectedService, selectedServices);

                if (serviceIndex > -1)
                {
                    selectedServices[serviceIndex].Notify = !selectedServices[serviceIndex].Notify;
                }
            }
        }

        private void runInBackgroundToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void frmMain_Resize(object sender, EventArgs e)
        {
            if (FormWindowState.Minimized == this.WindowState)
            {
                mynotifyicon.Visible = true;
                mynotifyicon.ShowBalloonTip(2000);
                this.ShowInTaskbar = false;
            }
        }
    }

    public class ServiceDetails
    {
        public string Name { get; set; }
        public string Title { get; set; }
        public bool RunWhenStopped { get; set; } = false;
        public bool Notify { get; set; } = false;

        public static ServiceDetails FindByTitle (string Title, List<ServiceDetails> services)
        {
            return services.Find(sc => sc.Title.Equals(Title));
        }

        public static ServiceDetails FindByName(string Name, List<ServiceDetails> services)
        {
            return services.Find(sc => sc.Name.Equals(Name));
        }

        public static int FindIndexByTitle(string Title, List<ServiceDetails> services)
        {
            return services.FindIndex(sc => sc.Title.Equals(Title));
        }

        public static int FindIndexByName(string Name, List<ServiceDetails> services)
        {
            return services.FindIndex(sc => sc.Name.Equals(Name));
        }
    }
}
